home *** CD-ROM | disk | FTP | other *** search
/ CD Classic 39 / CD CLASSIC #39 (1998).iso / EMPRESA / visio / Vistdstd / Install / Data.Z / Generic.C < prev    next >
C/C++ Source or Header  |  1996-09-27  |  21KB  |  595 lines

  1. /*    GENERIC.C - Source for Automation Demo Code in C
  2.  *  Copyright (C) 1991-1996 Visio Corporation. All rights reserved.
  3.  *
  4.  *
  5.  *    You have a royalty-free right to use, modify, reproduce and distribute
  6.  *    the Sample Application Files (and/or any modified version) in any way
  7.  *    you find useful, provided that you agree that Visio has no warranty,
  8.  *    obligations or liability for any Sample Application Files.
  9.  *
  10.  *
  11.  *    NEW IN 4.1:
  12.  *    This example has been modified from the form that shipped with Visio 
  13.  *    4.0 to demonstrate the new 4.1 capability to establish a connection 
  14.  *    from Visio to a controlling program over which event notifications are 
  15.  *    sent. RunDemo, in addition to creating a very simple organization chart,
  16.  *    which it has always done, now:
  17.  *
  18.  *        1.     Instantiates a "Visio sink object" (see addsink.h/c).
  19.  *        2.    Tells an IVEventList to a add connection over which document created
  20.  *            notifications will be sent from Visio to this program. The 
  21.  *            connection is set up so that ReceiveNotifyFromVisio (implemented 
  22.  *            herein) will be called after Visio creates a document.
  23.  *        3.    ReceiveNotifyFromVisio beeps and sets some local variables 
  24.  *            to values calculated from arguments passed to it. The beep will 
  25.  *            tell you the event proc got called. By setting breaks in and 
  26.  *            stepping through ReceiveNotifyFromVisio, you can see how you 
  27.  *            might write your own event handler procedures.
  28.  *        4.    Before returning, RunDemo releases the sink object made in step 1.
  29.  *
  30.  *    To find where these these steps are performed, search for "EVENT DEMO STUFF".
  31.  */
  32.  
  33. #include "visioc.h"
  34.  
  35. #include "resource.h"
  36.  
  37. //---BEGIN EVENT DEMO STUFF---
  38.  
  39. // The advise sink object we're going to use is declared in addsink.h.
  40. // You'll need to build addsink.cpp into your project as well.
  41. //
  42. // Note that you needn't use the addsink services if you don't want to.
  43. // You can implement your own connections directly with the more fundamental
  44. // methods and properties that Visio itself actually exposes. But addsink
  45. // packages up many of the details of talking idispatch.
  46. //
  47. #include "addsink.h"
  48.  
  49. // We're going to keep a static around that points to the sink object we 
  50. // instantiate. Your program, of course, could choose to do things more nicely.
  51. // Remember, this is just a demonstration. 
  52. //
  53. static LPUNKNOWN stc_ipSink = NULL;
  54. static long stc_nEventID= visEvtIDInval;
  55.  
  56. // This declares the event handling procedure we're going to tell stc_ipSink
  57. // to call when it receives notifications from Visio. The signature of
  58. // ReceiveNotifyFromVisio must conform to VISEVENTPROC. See addsink.h
  59. //
  60. HRESULT STDMETHODCALLTYPE ReceiveNotifyFromVisio (
  61.     IUnknown FAR*    ipSink,
  62.     WORD            wEvent,     // i: code of firing event (visEvt*; visio.h)
  63.     IUnknown FAR*    ipSource,     // i: object that's firing event [don't assert]
  64.     DWORD            dwEventID,    // i: id of event in ipsource that's firing
  65.     DWORD            dwEventSeq,    // i: sequence number of event that's firing
  66.     IUnknown FAR*    ipSubject,    // i: object event is about [don't assert]
  67.     VARIANT            eventExtra);// i: other info about event
  68.  
  69. //---END EVENT DEMO STUFF---
  70.  
  71. /**************************************************************************
  72.  *+ RunDemo
  73.  *
  74.  *  This demo will drive Visio through OLE Automation in C and draws a
  75.  *    simple orgizational chart on a Visio page.  Notice that the properties
  76.  *    and methods are no different than those called through VB, it's just
  77.  *    that you have the overhead of VARIANTs and pointer validation that VB
  78.  *    does for you.
  79.  *
  80.  *    Comments are spread throughout the code to explain the how and why
  81.  *    of programming Visio through OLE Automation.  Some of these comments
  82.  *    are directed at Visual Basic programmers who are making the transition
  83.  *    from OLE Automation under VB to C/C++.
  84.  */
  85. int RunDemo(void)
  86.     {
  87.     /* Declarations Section
  88.      *
  89.      * INTERFACES
  90.      *
  91.      *    In this example we're going to work with many different Visio
  92.      *    interfaces so we need a pointer to each one.  If you're coming from
  93.      *    the Visual Basic world you need to get used to the idea of 
  94.      *    releasing interfaces and verifying interface pointers before
  95.      *    invoking a method or property.  Visual Basic automatically does
  96.      *    a release for you whenever Object variables go out of scope or
  97.      *    whenever you do an explicit Set obj = Nothing.  However in C/C++
  98.      *    you must always release an interface when done with it and, when
  99.      *    given an interface, must verify that the pointer is != NULL before
  100.      *    attempting to invoke properties or methods on it.  In VB this is
  101.      *    equivalent to asking (obj Is Nothing).
  102.      *
  103.      *    Notice that we use the prefix ipIV for all our interface pointers.
  104.      *    ip stands for "Interface Pointer" and IV stands for
  105.      *    "Interface-Visio".  After that we put a descriptive name of the
  106.      *    interface we're pointing to.
  107.      *
  108.      *    An important thing to notice is that for every interface pointer
  109.      *    declared, there is a corresponding Release() call for it in the 
  110.      *    clean up (CU:) section at the bottom of RunDemo.  This is to
  111.      *    ensure that we release our lock upon the interface.  For more
  112.      *    information on the Release function see the OLE documentation.
  113.      *
  114.      * BSTRs & VARIANTs
  115.      *
  116.      *    Just like in Visual Basic, we have to pass parameters to our
  117.      *    properties and methods.  Because we are talking to OLE we need to 
  118.      *    pass strings as BSTRs.  These are allocated/deallocated using the
  119.      *    SysAllocString and SysFreeString functions provided by OLE.
  120.      *    Furthermore, properties and methods that can take more than one
  121.      *    data type for the same parameter will use the VARIANT type.  These
  122.      *    must be handled through the VariantInit, VariantClear functions and
  123.      *    the V_VT and V_type macros.  See the OLE documentation for more
  124.      *    information on manipulating both the BSTR and VARIANT data types.
  125.      */
  126.      
  127.     LPVISIOAPPLICATION ipIVApp       = NULL;
  128.     LPVISIODOCUMENTS   ipIVDocs      = NULL;
  129.     LPVISIODOCUMENT    ipIVDoc       = NULL;
  130.     LPVISIOPAGES       ipIVPages     = NULL;
  131.     LPVISIOPAGE        ipIVPage      = NULL;
  132.     LPVISIOSHAPE       ipIVShape     = NULL;
  133.     LPVISIOSHAPE       ipIVShape1    = NULL;
  134.     LPVISIOMASTERS     ipIVMasters   = NULL;
  135.     LPVISIOMASTER      ipIVMaster    = NULL;
  136.     LPVISIODOCUMENT    ipIVStencil   = NULL;
  137.     LPVISIOCELL        ipIVCell      = NULL;
  138.     LPVISIOCELL        ipIVCell1     = NULL;
  139.     LPVISIOEVENTS      ipIVEventList = NULL;
  140.     LPVISIOEVENT       ipIVEvent     = NULL;
  141.     BSTR bstr = NULL;
  142.     VARIANT variant;
  143.     HRESULT hResult;
  144.  
  145.     /* STARTING VISIO
  146.      *
  147.      *    A special utility file is included called IVISREG that does
  148.      *    the work of getting a Visio application interface.  This file
  149.      *    is equivalent to the VISREG.BAS file for Visual Basic.
  150.      *
  151.      *    To see how it works open the file and examine it's function calls.
  152.      *    We use a simple, one parameter function that gets the active
  153.      *    instance if one exists or creates a new one if one is not running.
  154.      */
  155.      
  156.     if ( VAO_SUCCESS != vaoGetObject(&ipIVApp) )
  157.         goto CU;
  158.  
  159.     //---BEGIN EVENT DEMO STUFF---
  160.     //
  161.     // Search progref.hlp for AddAdvise for more information on event handling.
  162.     // What we do is:
  163.     //
  164.     //    1.    Verify the version of the instance of Visio we just got a 
  165.     //        reference to is a version that supports event notification.
  166.     //        If vaoGetObject succeeds with this compile, then it is.
  167.     //    2.    Provided Visio is new enough, we then make a sink object. 
  168.     //    3.    We call AddAdvise on the EventList object which will cause
  169.     //        ReceiveNotifyFromVisio to be called after Visio creates a document.
  170.     //        The event source (the object that will fire the notifications back to 
  171.     //        this program) is the app (ipIVApp) we just made. (In general,
  172.     //        the source object is the one which owns the EventList.)
  173.  
  174.     // assert !stc_ipSink
  175.     if (SUCCEEDED(CoCreateAddonSink(ReceiveNotifyFromVisio, &stc_ipSink)))
  176.         {
  177.         if (SUCCEEDED(ipIVApp->lpVtbl->get_EventList(ipIVApp, &ipIVEventList)))
  178.             {
  179.             BSTR bstr= NULL;
  180.             VARIANT v;
  181.  
  182.             VariantInit(&v);
  183.             V_VT(&v) = VT_UNKNOWN;
  184.             V_UNKNOWN(&v) = stc_ipSink;
  185.  
  186.             if (SUCCEEDED(ipIVEventList->lpVtbl->AddAdvise(ipIVEventList, visEvtCodeDocCreate,
  187.                     v, bstr, bstr, &ipIVEvent)))
  188.                 {
  189.                 ipIVEvent->lpVtbl->get_ID(ipIVEvent, &stc_nEventID);
  190.  
  191.                 ipIVEvent->lpVtbl->Release(ipIVEvent);
  192.                 ipIVEvent= NULL;
  193.                 }
  194.  
  195.             ipIVEventList->lpVtbl->Release(ipIVEventList);
  196.             ipIVEventList= NULL;
  197.             }
  198.  
  199.         // If Add didn't work, dwEventID will equal visEvtIDInval.
  200.  
  201.         // If Add worked, dwEventID is the id of the Event (IVEvent)
  202.         // object that got created in the EventList (IVEventList) of
  203.         // ipIVApp and ReceiveNotifyFromVisio will henceforth get called
  204.         // after Visio creates a document. 
  205.         //
  206.         // If, for some reason, we were to later decide to terminate 
  207.         // the connection we just made, we could do so by calling Delete
  208.         // in the IVEvent interface.
  209.  
  210.         stc_ipSink->lpVtbl->Release(stc_ipSink);
  211.         stc_ipSink= NULL;
  212.         }
  213.     //---END EVENT DEMO STUFF---
  214.  
  215.     /*  Next we start the main work of drawing an organization chart.  
  216.      *    First we retrieve the Documents collection and try to add a blank
  217.      *    document based on the SAMPLE.VST template. The workspace of this
  218.      *    template refers to the SAMPLE.VSS stencil file, which has some
  219.      *    masters we'll use to make the org chart with.
  220.      *
  221.      *    To demonstrate an invoke let's look at how we retrieve the 
  222.      *    Documents property of the Application interface.  First off, 
  223.      *    every property and method returns an HRESULT and if we want
  224.      *    to see if the call passed or failed we use the SUCCEEDED macro to
  225.      *    examine the SCODE contained in the HRESULT. If the call fails then
  226.      *    we automatically go to clean up since we can't continue.
  227.      *
  228.      *    If the call succeeds we're still not done.  Next we have to check
  229.      *    that another interface pointer was returned and, if it was not,
  230.      *    we go to clean up once again.  This is the standard convention
  231.      *    that we'll use throughout the rest of the examples:
  232.      *
  233.      *        1) Make sure the call works
  234.      *        2) Verify an interface, if any, was returned.
  235.      *
  236.      *    Remember to check the pointers returned because if a call fails
  237.      *    and you try to call a method or property on a NULL pointer an
  238.      *    error will occur.
  239.      */
  240.      
  241.     // Get App.Documents property
  242.  
  243.     hResult = ipIVApp->lpVtbl->get_Documents(ipIVApp, &ipIVDocs);
  244.     
  245.     if ( !SUCCEEDED(hResult) )
  246.         goto CU;
  247.         
  248.     if ( !ipIVDocs )
  249.         goto CU;        
  250.     
  251.     /*  For this call notice that we have to allocate a BSTR.  We
  252.      *    always allocate the BSTR before the call and then immediately
  253.      *    after it.  This way we're guaranteed we don't have a memory leak
  254.      *    However, this limits us from jumping straight to clean up as in
  255.      *    the previous example, thus we store the HRESULT in a temporary
  256.      *    variable and check it after deallocating the BSTR.
  257.      */
  258.      
  259.     // Add a blank document with Docs.Add
  260.     
  261.     bstr = SysAllocString(OLESTR("sample.vst"));
  262.     hResult = ipIVDocs->lpVtbl->Add(ipIVDocs, bstr, &ipIVDoc);
  263.     SysFreeString(bstr);
  264.     
  265.     if ( !SUCCEEDED(hResult) || !ipIVDoc )
  266.         goto CU;
  267.     
  268.     // Get blank document Pages collection using Doc.Pages
  269.     
  270.     hResult = ipIVDoc->lpVtbl->get_Pages(ipIVDoc, &ipIVPages);
  271.     
  272.     if ( !SUCCEEDED(hResult) || !ipIVPages )
  273.         goto CU;
  274.      
  275.     /*  For this call we need to use a variant for the Pages.Item property.
  276.      *    Because Pages.Item can take either a string containing the page's
  277.      *    name or an integer specifying the page's index we need to put pass
  278.      *    a VARIANT.  Notice that we first init the variant, then set the
  279.      *    type of it with the V_VT macro to I2, meaning 2 byte integer.  Then
  280.      *    we use the V_I2 macro to set the variant's value.  After that we
  281.      *    can make the call.  Once the call has returned, though, we need
  282.      *    to clear the variant.  Read up on VARIANTs in the OLE 2.0 Programmer's
  283.      *    Reference to see exactly how to work with them and for a listing of
  284.      *    their support functions and macros.
  285.      */
  286.      
  287.     // Get first page of blank document using Pages.Item
  288.     
  289.     VariantInit(&variant);
  290.     V_VT(&variant) = VT_I2;
  291.     V_I2(&variant) = 1;
  292.     hResult = ipIVPages->lpVtbl->get_Item(ipIVPages, variant, &ipIVPage);
  293.     VariantClear(&variant);
  294.     
  295.     if ( !SUCCEEDED(hResult) || !ipIVPage )
  296.         goto CU;
  297.     
  298.     // Get Document interface for sample stencil using Docs.Item
  299.     
  300.     VariantInit(&variant);
  301.     V_VT(&variant) = VT_BSTR;
  302.     V_BSTR(&variant) = SysAllocString(OLESTR("sample.vss"));
  303.     hResult = ipIVDocs->lpVtbl->get_Item(ipIVDocs, variant, &ipIVStencil);
  304.     VariantClear(&variant);
  305.     
  306.     if ( !SUCCEEDED(hResult) || !ipIVStencil )
  307.         goto CU;
  308.     
  309.     // Retrieve Masters interface using Doc.Masters
  310.     
  311.     hResult = ipIVStencil->lpVtbl->get_Masters(ipIVStencil, &ipIVMasters);
  312.     
  313.     if ( !SUCCEEDED(hResult) || !ipIVMasters )
  314.         goto CU;
  315.     
  316.     // Get Executive master using Masters.Item
  317.     
  318.     VariantInit(&variant);
  319.     V_VT(&variant) = VT_BSTR;
  320.     V_BSTR(&variant) = SysAllocString(OLESTR("Executive"));
  321.     hResult = ipIVMasters->lpVtbl->get_Item(ipIVMasters, variant, &ipIVMaster);
  322.     VariantClear(&variant);
  323.     
  324.     if ( !SUCCEEDED(hResult) || !ipIVMaster )
  325.         goto CU;
  326.     
  327.     // Drop Executive master using Page.Drop
  328.     
  329.     hResult = ipIVPage->lpVtbl->Drop(ipIVPage,
  330.                                      (LPUNKNOWN)ipIVMaster,
  331.                                      6.0,
  332.                                      6.0,
  333.                                      &ipIVShape );
  334.     
  335.     if ( !SUCCEEDED(hResult) || !ipIVShape )
  336.         goto CU;
  337.         
  338.     /*  At this point we want to re-use the one master interface we
  339.      *    declaraed.  To do it we must first release and then set it
  340.      *    to NULL.  Not setting it to NULL could cause serious problems later
  341.      *    so remember to do this, especially when iterating collections.
  342.      */
  343.      
  344.     if ( ipIVMaster )
  345.         {
  346.         ipIVMaster->lpVtbl->Release(ipIVMaster);
  347.         ipIVMaster = NULL;
  348.         }
  349.         
  350.     // Get Position 1 master using Masters.Item
  351.     
  352.     VariantInit(&variant);
  353.     V_VT(&variant) = VT_BSTR;
  354.     V_BSTR(&variant) = SysAllocString(OLESTR("Position"));
  355.     hResult = ipIVMasters->lpVtbl->get_Item(ipIVMasters, variant, &ipIVMaster);
  356.     VariantClear(&variant);
  357.     
  358.     if ( !SUCCEEDED(hResult) || !ipIVMaster )
  359.         goto CU;
  360.     
  361.     // Drop Position 1 master using Page.Drop
  362.     
  363.     hResult = ipIVPage->lpVtbl->Drop(ipIVPage,
  364.                                      (LPUNKNOWN)ipIVMaster,
  365.                                      3.0,
  366.                                      3.0,
  367.                                      &ipIVShape1 );
  368.                                      
  369.     if ( !SUCCEEDED(hResult) || !ipIVShape1 )
  370.         goto CU;
  371.     
  372.     // Get Executive's Connection point using Shape.Cells
  373.     
  374.     bstr = SysAllocString(OLESTR("Connections.X4"));
  375.     hResult = ipIVShape->lpVtbl->get_Cells(ipIVShape, bstr, &ipIVCell);
  376.     SysFreeString(bstr);
  377.     
  378.     if ( !SUCCEEDED(hResult) || !ipIVCell )
  379.         goto CU;
  380.     
  381.     // Get Position 1's Control handle using Shape.Cells
  382.     
  383.     bstr = SysAllocString(OLESTR("Controls.X1"));
  384.     hResult = ipIVShape1->lpVtbl->get_Cells(ipIVShape1, bstr, &ipIVCell1);
  385.     SysFreeString(bstr);
  386.     
  387.     if ( !SUCCEEDED(hResult) || !ipIVCell )
  388.         goto CU;
  389.     
  390.     // Glue Position 1 to Executive using Cell.Glue
  391.    
  392.     hResult = ipIVCell1->lpVtbl->GlueTo(ipIVCell1, ipIVCell);
  393.     
  394.     if ( !SUCCEEDED(hResult) )
  395.         goto CU;
  396.     
  397. CU: /* CLEANUP
  398.      *
  399.      *    The clean up section is meant to release any interface pointers
  400.      *    that are outstanding at this point.  Our example does not need to
  401.      *    keep any around for later use or to pass back to our caller so we
  402.      *    release every one.  However, if we were going to, say, pass one
  403.      *    back to a calling function as the call vaoGetObject does we would
  404.      *    not want to release it.
  405.      */
  406.  
  407.     //---BEGIN EVENT DEMO STUFF---
  408.     // We're going to get rid of the event sink object we made in the event
  409.     // demo stuff scope above. If stc_ipSink is presently managing any 
  410.     // connections from Visio to this program, VisSink_Destroy() first 
  411.     // disconnects then. Then it releases stc_ipSink and sets it to null. 
  412.     // VisSink_Destroy() can validly be called if stc_ipSink is null.
  413.  
  414. //    VisSink_Destroy(&stc_ipSink);
  415.     // assert !stc_ipSink
  416.  
  417.     //---END EVENT DEMO STUFF---
  418.      
  419.     if ( ipIVCell1 )
  420.         ipIVCell1->lpVtbl->Release(ipIVCell1);
  421.     if ( ipIVCell )
  422.         ipIVCell->lpVtbl->Release(ipIVCell);
  423.     if ( ipIVStencil )
  424.         ipIVStencil->lpVtbl->Release(ipIVStencil);
  425.     if ( ipIVMaster )
  426.         ipIVMaster->lpVtbl->Release(ipIVMaster);
  427.     if ( ipIVMasters )
  428.         ipIVMasters->lpVtbl->Release(ipIVMasters);
  429.     if ( ipIVShape1 )
  430.         ipIVShape1->lpVtbl->Release(ipIVShape1);
  431.     if ( ipIVShape )
  432.         ipIVShape->lpVtbl->Release(ipIVShape);
  433.     if ( ipIVPage )
  434.         ipIVPage->lpVtbl->Release(ipIVPage);
  435.     if ( ipIVPages )
  436.         ipIVPages->lpVtbl->Release(ipIVPages);
  437.     if ( ipIVDoc )
  438.         ipIVDoc->lpVtbl->Release(ipIVDoc);
  439.     if ( ipIVDocs )
  440.         ipIVDocs->lpVtbl->Release(ipIVDocs);
  441.     if ( ipIVApp )
  442.         ipIVApp->lpVtbl->Release(ipIVApp);
  443.     
  444.     return 0;
  445.     }
  446.     
  447. //---BEGIN EVENT DEMO STUFF---
  448.  
  449. /***********************************************************************
  450.  *+ ReceiveNotifyFromVisio
  451.  *
  452.  *    Gets called when Visio sends an event nofification over a connection 
  453.  *    that this program has set up and which is being managed by the stc_ipSink
  454.  *    object instantiated in RunDemo.
  455.  */
  456. HRESULT STDMETHODCALLTYPE ReceiveNotifyFromVisio ( 
  457.     IUnknown FAR*    ipSink,        // i: calling sink [assert]
  458.     WORD            wEvent,     // i: code of firing event (visEvt*; visconst.h)
  459.     IUnknown FAR*    ipSource,     // i: object firing event [don't assert]
  460.     DWORD            dwEventID,    // i: id of event in ipsource that's firing
  461.     DWORD            dwEventSeq,    // i: sequence number of event that's firing
  462.     IUnknown FAR*    ipSubject,    // i: object event is about [don't assert]
  463.     VARIANT            eventExtra)    // i: other info about event
  464. {
  465.     BOOL bUnexpected= FALSE;
  466.  
  467.     MessageBeep(MB_OK);
  468.  
  469.  
  470.     //    QueryInterface for the Application interface on the IUnknown ipSource.
  471.     //    The ipSource interface pointer, if it is non-NULL, points to
  472.     //    the Application which owns the EventList which fired this event.
  473.     //    To get the Event object, use the EventList::ItemFromID method.
  474.  
  475.     if (ipSource!=NULL)
  476.     {
  477.         LPVISIOAPPLICATION pApp= NULL;
  478.  
  479.         bUnexpected= TRUE;    //    assume until...
  480.  
  481.         if (SUCCEEDED(ipSource->lpVtbl->QueryInterface(ipSource, &IID_IVApplication, (LPVOID *) &pApp)))
  482.             {
  483.             LPVISIOEVENTS pList= NULL;
  484.             LPVISIOEVENT pEvt= NULL;
  485.  
  486.             if (SUCCEEDED(pApp->lpVtbl->get_EventList(pApp, &pList)) && NULL!=pList)
  487.             {
  488.                 if (SUCCEEDED(pList->lpVtbl->get_ItemFromID(pList, stc_nEventID, &pEvt)) && NULL!=pEvt)
  489.                 {
  490.                     short wEventProp;
  491.                     if (SUCCEEDED(pEvt->lpVtbl->get_Event(pEvt, &wEventProp)))
  492.                     {
  493.                         if (wEventProp==wEvent)
  494.                             bUnexpected= FALSE;        //    ...proven otherwise
  495.                     }
  496.  
  497.                     pEvt->lpVtbl->Release(pEvt);
  498.                 }
  499.  
  500.                 pList->lpVtbl->Release(pList);
  501.             }
  502.  
  503.             pApp->lpVtbl->Release(pApp);
  504.         }
  505.     }
  506.  
  507.  
  508.     //    QueryInterface for the document interface on the IUnknown ipSubject.
  509.     //    The ipSubject interface pointer, if it is non-NULL, should be able to give us
  510.     //    back a Document since we signed up for a 'Document Created' event.
  511.  
  512.     if (ipSubject!=NULL)
  513.     {
  514.         LPVISIODOCUMENT pDoc= NULL;
  515.  
  516.         bUnexpected= TRUE;    //    assume until...
  517.  
  518.         if (SUCCEEDED(ipSubject->lpVtbl->QueryInterface(ipSubject, &IID_IVDocument, (LPVOID *) &pDoc)))
  519.         {
  520.             short objType;
  521.  
  522.             if ( NULL!=pDoc && SUCCEEDED(pDoc->lpVtbl->get_ObjectType(pDoc, &objType)) && (objType==visObjTypeDoc) )
  523.             {
  524.                 short sSaved;
  525.                 if ( SUCCEEDED(pDoc->lpVtbl->get_Saved(pDoc, &sSaved)) && sSaved )
  526.                     bUnexpected= FALSE;        //    ...proven otherwise
  527.             }
  528.  
  529.             pDoc->lpVtbl->Release(pDoc);
  530.         }
  531.     }
  532.  
  533.  
  534.     //    Screech if unexpected condition was encountered:
  535.     if ( bUnexpected )
  536.     {
  537.         int i= 0;
  538.         for ( ; i < 30; i++ )
  539.             MessageBeep((UINT)-1);
  540.     }
  541.  
  542.     return NOERROR;
  543. }
  544.  
  545. //---END EVENT DEMO STUFF---
  546.  
  547. /***********************************************************************
  548.  *+ AboutDlgProc
  549.  *
  550.  */
  551. #ifdef __BORLANDC__
  552. #pragma argsused
  553. #endif 
  554.  
  555. #ifdef _DLL
  556. BOOL __loadds CALLBACK AboutDlgProc(
  557. #else
  558. BOOL CALLBACK AboutDlgProc(
  559. #endif
  560.     HWND hDlg,
  561.     UINT msg,
  562.     WPARAM wParam,
  563.     LPARAM lParam)
  564.     {
  565.     switch (msg)
  566.         {
  567.         case WM_COMMAND:
  568.             switch (wParam)
  569.                 {
  570.                 case IDOK:
  571.                 case IDCANCEL:
  572.                     EndDialog(hDlg, TRUE);
  573.                     return (TRUE);
  574.                 }
  575.         }
  576.     
  577.     return (FALSE);
  578.     }
  579.  
  580. /***********************************************************************
  581.  *+ ShowAboutDialog
  582.  *
  583.  *    Displays the help about dialog.
  584.  */
  585. void ShowAboutDialog(HINSTANCE hInstance)
  586.     {
  587.     FARPROC lpProcDlg = NULL;
  588.     
  589.     lpProcDlg = MakeProcInstance((FARPROC)AboutDlgProc, hInstance);
  590.  
  591.     DialogBox(hInstance, "ABOUTBOX", NULL, lpProcDlg);
  592.            
  593.     FreeProcInstance(lpProcDlg);
  594.     };
  595.